#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "editorfactory.h"


#include <characterclass.h>
#include <skill.h>
#include <specialability.h>
#include <feat.h>

#include <xmlserializer.h>


#include <QActionGroup>
#include <QFileDialog>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>
#include <QSortFilterProxyModel>
#include <QPointer>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    qRegisterMetaType<Campaign*>();
    m_campaign = 0;
    m_model = new DTwentyModel(this);
    QSortFilterProxyModel* sortFilter = new QSortFilterProxyModel(this);
    sortFilter->setSourceModel(m_model);
    sortFilter->setDynamicSortFilter(true);

    ui->setupUi(this);
    insertToolBar(ui->toolBarView, ui->toolBarEdit);
    insertToolBarBreak(ui->toolBarView);


    ui->toolBarEdit->addAction(ui->actionSave);
    ui->toolBarEdit->addSeparator();
    ui->toolBarEdit->addActions(ui->menu_Edit->actions());
    ui->toolBarView->addActions(ui->menu_View->actions());



    QActionGroup* actionGroup = new QActionGroup(this);
    actionGroup->addAction(ui->actionCharacter_Classes);
    actionGroup->addAction(ui->actionFeats);
    actionGroup->addAction(ui->actionSkills);
    actionGroup->addAction(ui->actionSpecials);

    ui->centralWidget->setEnabled(false);


    ui->listView->setModel(sortFilter);
}

MainWindow::~MainWindow()
{
    delete ui;
}


bool MainWindow::closeCampaign(bool allowCancel)
{
    if (!m_campaign)
    {
        return true;
    }

    int result = -1;
    if (allowCancel)
    {
        result = QMessageBox::question(this, tr("Save Campaign?"), tr("Do you want to save current campaign?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    }
    else
    {
        result = QMessageBox::question(this, tr("Save Campaign?"), tr("Do you want to save current campaign?"), QMessageBox::Yes | QMessageBox::No);
    }

    switch (result)
    {
    case QMessageBox::Cancel:
        return false;

    case QMessageBox::Yes:
        on_actionSave_triggered();
        break;

    case QMessageBox::No:
        break;

    default:
        return false;
    }

    foreach (QPointer<QDialog> d, m_editorDialogs.values())
    {
        if (d.isNull())
        {
            continue;
        }

        d->close();
    }

    m_editorDialogs.clear();

    m_model->setRoot(0);

    m_campaign->setParent(0);
    m_campaign->deleteLater();
    m_campaign = 0;

    ui->centralWidget->setEnabled(false);

    return true;
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    closeCampaign(false);

    QMainWindow::closeEvent(e);
}

void MainWindow::initialize()
{
    ui->lineEditCampaignName->setText("");

    if (!m_model || !m_model->root())
    {
        return;
    }


    QString name = m_model->root()->name();
    ui->lineEditCampaignName->setText(name);

    ui->centralWidget->setEnabled(true);

    ui->actionSkills->setChecked(true);
    setViewRootIndex(qMetaTypeId<Skills*>());
    ui->listView->model()->sort(0);

}

void MainWindow::setViewRootIndex(int metaTypeId)
{
    QAbstractItemModel* model = ui->listView->model();

    QModelIndex start = model->index(0, 0, QModelIndex());
    if (!start.isValid())
    {
        qDebug() << Q_FUNC_INFO << "No valid start index!";
        return;
    }

    QModelIndexList indexes = model->match(start, DTwentyModel::Role_TYPE, metaTypeId, 1, Qt::MatchExactly);
    if (indexes.isEmpty())
    {
        qDebug() << Q_FUNC_INFO << "No character classes container!";
        return;
    }

    QModelIndex index = indexes.first();

    ui->listView->setRootIndex(index);
    ui->labelCampaignItemsTitle->setText(tr("%1:").arg(index.data().toString()));
}


void MainWindow::on_actionNew_triggered()
{
    if (!closeCampaign())
    {
        return;
    }

    m_campaign = new Campaign(this);
    m_campaign->setName(tr("New Campaign"));
    m_model->setRoot(m_campaign);

    QTimer::singleShot(0, this, SLOT(initialize()));
}

void MainWindow::on_actionOpen_triggered()
{
    if (!closeCampaign())
    {
        return;
    }

    QString fileName = QFileDialog::getOpenFileName(this, tr("Open Campaign File"), QDir::currentPath(), tr("Xml Files (*.xml)"));
    if (fileName.isEmpty())
    {
        return;
    }

    static QString errTitle = tr("Open Failed!");
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly))
    {
        QMessageBox::warning(this, errTitle, tr("Can't open file!"));
        return;
    }

    XmlSerializer serializer;
    Campaign* campaign = qobject_cast<Campaign*>(serializer.deserialize(&file));

    if (!campaign)
    {
        QMessageBox::warning(this, errTitle, QString("%1\n%2").arg(tr("Can't open campaing file!")).arg(serializer.error()));
        return;
    }

    m_fileName = fileName;
    m_campaign = campaign;
    m_campaign->setParent(this);
    m_model->setRoot(m_campaign);

    QTimer::singleShot(0, this, SLOT(initialize()));

}

void MainWindow::on_actionSave_As_triggered()
{
    if (!m_campaign)
    {
        return;
    }

    QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), QDir::currentPath(), tr("Xml Files (*.xml)"));
    if (fileName.isEmpty())
    {
        return;
    }

    QFile file(fileName);
    if (!file.open(QFile::WriteOnly))
    {
        QMessageBox::warning(this, tr("File Save Failed!"), tr("Can't save file!"));
        return;
    }

    on_lineEditCampaignName_editingFinished();

    XmlSerializer serializer;
    serializer.serialize(m_campaign, &file);

    m_fileName = fileName;

}

void MainWindow::on_actionSave_triggered()
{
    if (!m_campaign)
    {
        return;
    }

    if (m_fileName.isEmpty())
    {
        on_actionSave_As_triggered();
        return;
    }

    QFile file(m_fileName);
    if (!file.open(QFile::WriteOnly))
    {
        QMessageBox::warning(this, tr("File Save Failed!"), tr("Can't save file!"));
        return;
    }

    on_lineEditCampaignName_editingFinished();

    XmlSerializer serializer;
    serializer.serialize(m_campaign, &file);

}

void MainWindow::on_actionQuit_triggered()
{
    if (!closeCampaign())
    {
        return;
    }

    close();
}


void MainWindow::on_lineEditCampaignName_editingFinished()
{
    if (!m_model || !m_model->root())
    {
        return;
    }

    m_model->root()->setName(ui->lineEditCampaignName->text());
}

void MainWindow::on_actionSkills_triggered()
{
    setViewRootIndex(qMetaTypeId<Skills*>());
}

void MainWindow::on_actionFeats_triggered()
{
    setViewRootIndex(qMetaTypeId<Feats*>());
}

void MainWindow::on_actionSpecials_triggered()
{
    setViewRootIndex(qMetaTypeId<SpecialAbilities*>());
}

void MainWindow::on_actionCharacter_Classes_triggered()
{
    setViewRootIndex(qMetaTypeId<CharacterClasses*>());
}

void MainWindow::on_actionDelete_triggered()
{
    ui->listView->model()->removeRow(ui->listView->currentIndex().row(), ui->listView->rootIndex());
}

void MainWindow::on_actionNew_Item_triggered()
{
    QSortFilterProxyModel* proxy = qobject_cast<QSortFilterProxyModel*>(ui->listView->model());
    int row = proxy->rowCount(ui->listView->rootIndex());
    if (!proxy->insertRows(row, 1, ui->listView->rootIndex()))
    {
        qDebug() << Q_FUNC_INFO << "Can't insert rows!";
        return;
    }

    QModelIndex sourceParent = proxy->mapToSource(ui->listView->rootIndex());
    QModelIndex sourceIndex = proxy->sourceModel()->index(row, 0, sourceParent);
    QModelIndex proxyIndex = proxy->mapFromSource(sourceIndex);

    if (!proxyIndex.isValid())
    {
        qDebug() << Q_FUNC_INFO << "Can't find created proxy index!";
        return;
    }

    ui->listView->setCurrentIndex(proxyIndex);


}


void MainWindow::on_actionEdit_triggered()
{
    QSortFilterProxyModel* proxyModel = qobject_cast<QSortFilterProxyModel*>(ui->listView->model());
    if (!proxyModel->sourceModel())
    {
        return;
    }

    QModelIndex index = proxyModel->mapToSource(ui->listView->currentIndex());
    if (!index.isValid())
    {
        return;
    }

    if (m_editorDialogs.contains(index))
    {
        QPointer<QDialog> d = m_editorDialogs.value(index);
        if (!d.isNull())
        {
            d->show();
            d->raise();
            return;
        }
    }


    AbstractEditor* editor = EditorFactory::editorWidget(index);
    if (!editor)
    {
        return;
    }


    editor->setEditorData(proxyModel->sourceModel(), index);


    QPointer<QDialog> d = new QDialog();
    m_editorDialogs.insert(index, d);
    d->setAttribute(Qt::WA_DeleteOnClose, true);


    QVBoxLayout* l = new QVBoxLayout(d);
    editor->setParent(d);
    l->addWidget(editor);

    QAction* a = new QAction(tr("Close"), d);
    a->setShortcut(QKeySequence(tr("Ctrl+W")));
    d->addAction(ui->actionSave);
    d->addAction(a);

    d->resize(800,600);
    d->setWindowTitle(index.sibling(index.row(), 0).data().toString());
    d->setModal(false);
    d->open();

}

